import { withUser, parseBody, json } from "@/lib/api"; import { getProjectDetail, updateProject, deleteProject, moveConversations, listUnassignedConversations } from "@/lib/projects/service"; import { projectBodySchema, projectActionSchema } from "@/lib/projects/schemas"; export const dynamic = "force-dynamic"; type P = { id: string }; /** GET /api/projects/:id → { project, conversations, files, prompts, stats } ; `?unassigned=1` → { conversations } outside any project. */ export const GET = withUser
(async ({ req, user }, { id }) => { if (new URL(req.url).searchParams.get("unassigned") === "1") return json({ conversations: await listUnassignedConversations(user.id) }); return json(await getProjectDetail(user.id, id)); }); /** PATCH /api/projects/:id (any subset of the create body) → { project } */ export const PATCH = withUser
(async ({ req, user }, { id }) => { const body = await parseBody(req, projectBodySchema.partial()); return json({ project: await updateProject(user.id, id, body) }); }); /** POST /api/projects/:id { action: "add-conversations" | "remove-conversations", conversationIds } → { moved } */ export const POST = withUser
(async ({ req, user }, { id }) => { const body = await parseBody(req, projectActionSchema); const moved = await moveConversations(user.id, body.conversationIds, body.action === "add-conversations" ? id : null); return json({ moved }); }); /** DELETE /api/projects/:id — conversations are kept (project_id → null); files cascade; prompts are detached. */ export const DELETE = withUser
(async ({ user }, { id }) => { await deleteProject(user.id, id); return json({ ok: true }); });